using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;

namespace Admin.NET.Application.Excel;

public static class ExportToExcel
{
	/// <summary>
	/// 导出通用封装基本支持
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="listInfo">导出内容</param>
	/// <param name="headerText">头部标题</param>
	/// <param name="sheetName">sheet标题</param>
	/// <param name="properName">字段对应内容</param>
	/// <param name="titleName">字段名称对应</param>
	/// <param name="dic">处理字典转换</param>
	/// <returns></returns>
	public static MemoryStream ExportToList<T>(T[] listInfo, string headerText, string sheetName, string[] properName, string[] titleName, Dictionary<string, Dictionary<string, string>> dic = null)
	{
		Stopwatch watch = new Stopwatch();
		watch.Start();
		if (properName.Length != titleName.Length)
		{
			return new MemoryStream();
		}
		XSSFWorkbook workbook = new XSSFWorkbook();
		ISheet sheet = workbook.CreateSheet(sheetName);
		ICellStyle dateStyle = workbook.CreateCellStyle();
		IDataFormat format = workbook.CreateDataFormat();
		dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd");
		int[] arrColWidth = new int[properName.Length];
		for (int i = 0; i < properName.Length; i++)
		{
			arrColWidth[i] = Encoding.UTF8.GetBytes(titleName[i]).Length;
		}
		Type ttype = typeof(T);
		PropertyInfo[] propertyinfos = ttype.GetProperties();
		for (int i = 0; i < listInfo.Length; i++)
		{
			for (int j = 0; j < properName.Length; j++)
			{
				int intTemp = Encoding.UTF8.GetBytes(ttype.GetProperty(properName[j]).GetValue(listInfo[i])?.ToString() ?? "").Length;
				if (intTemp > arrColWidth[j])
				{
					arrColWidth[j] = intTemp;
				}
			}
		}
		int rowIndex = 0;
		int irow = 0;
		foreach (T row in listInfo)
		{
			int icount = listInfo.Length;
			int i;
			if (rowIndex == 65535 || rowIndex == 0)
			{
				if (rowIndex != 0)
				{
					irow++;
					sheet = workbook.CreateSheet(sheetName + irow);
				}
				IRow headerRow = sheet.CreateRow(0);
				headerRow.HeightInPoints = 25f;
				headerRow.CreateCell(0).SetCellValue(headerText);
				ICellStyle headStyle = workbook.CreateCellStyle();
				headStyle.Alignment = HorizontalAlignment.Center;
				IFont font = workbook.CreateFont();
				font.FontHeightInPoints = 20.0;
				font.IsBold = true;
				headStyle.SetFont(font);
				headerRow.GetCell(0).CellStyle = headStyle;
				sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, properName.Length - 1));
				headerRow = sheet.CreateRow(1);
				headStyle = workbook.CreateCellStyle();
				headStyle.Alignment = HorizontalAlignment.Center;
				font = workbook.CreateFont();
				font.FontHeightInPoints = 10.0;
				font.IsBold = true;
				headStyle.SetFont(font);
				for (i = 0; i < properName.Length; i++)
				{
					headerRow.CreateCell(i).SetCellValue(titleName[i]);
					headerRow.GetCell(i).CellStyle = headStyle;
					sheet.SetColumnWidth(i, (arrColWidth[i] + 1) * 256);
				}
				rowIndex = 2;
			}
			IRow dataRow = sheet.CreateRow(rowIndex);
			for (i = 0; i < properName.Length; i++)
			{
				ICell newCell = dataRow.CreateCell(i);
				string drValue = ttype.GetProperty(properName[i]).GetValue(row)?.ToString() ?? "";
				if (dic != null && dic.Keys.Where((string u) => u == properName[i]).Any())
				{
					dic[properName[i]].TryGetValue(drValue, out var returnValue);
					newCell.SetCellValue(returnValue ?? "");
					continue;
				}
				switch (ttype.GetProperty(properName[i]).PropertyType.ToString())
				{
				case "System.String":
					newCell.SetCellValue(drValue);
					break;
				case "System.Nullable`1[System.DateTime]":
				case "System.DateTime":
				{
					DateTime.TryParse(drValue, out var dateV);
					newCell.SetCellValue(dateV);
					newCell.CellStyle = dateStyle;
					break;
				}
				case "System.Boolean":
				{
					bool boolV = false;
					bool.TryParse(drValue, out boolV);
					newCell.SetCellValue(boolV);
					break;
				}
				case "System.Int16":
				case "System.Int32":
				case "System.Int64":
				case "System.Byte":
				{
					int intV = 0;
					int.TryParse(drValue, out intV);
					newCell.SetCellValue(intV);
					break;
				}
				case "System.Decimal":
				case "System.Nullable`1[System.Decimal]":
				case "System.Double":
				{
					double doubV = 0.0;
					double.TryParse(drValue, out doubV);
					newCell.SetCellValue(doubV);
					break;
				}
				case "System.DBNull":
					newCell.SetCellValue("");
					break;
				default:
					newCell.SetCellValue("");
					break;
				}
			}
			rowIndex++;
		}
		using MemoryStream ms = new MemoryStream();
		workbook.Write(ms);
		sheet = null;
		workbook = null;
		watch.Stop();
		string time = watch.ElapsedMilliseconds.ToString();
		return ms;
	}
}
